package scene.composants;

import java.awt.AlphaComposite;
import java.awt.Color;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Point;
import java.io.Serializable;


import scene.composants.elements.*;

/**
 * Composant Graphique
 * Chaque composants peut derive de RepresentationComposant
 * La methode void dessiner(Graphics2D g2d) doit etre redefinit
 * Chaque composant possede son affichage et ses proprietes
 * 
 * @author Delmas Gabriel
 */
public abstract class RepresentationComposant implements IDessinableManipulable, Serializable
{
	/**
	 * Constante largeur minimum d'un composant 
	 */
	protected final int MIN_LARGEUR=100;
	
	/**
	 * Constante hauteur minimum d'un composant 
	 */
	protected final int MIN_HAUTEUR=100;
	
	/**
	 * Largeur minimum du composant
	 */
	protected int minLargeur=100;
	
	/**
	 * Hauteur minimum du composant
	 */
	protected int minHauteur=100;
	
	/**
	 * Largeur du composant
	 */
	protected int largeur=100;
	
	/**
	 * Hauteur du composant
	 */
	protected int hauteur=100;
	
	/**
	 * Position (coin haut gauche) du composant 
	 */
	protected Point p;
	
	/**
	 * Dimensions du composant (sa surface)
	 */
	protected Rectangle cadre;
	
	/**
	 * Taille en pixel de l'espacement des ecritures
	 */
	protected int espace_texte=12;
	
	/**
	 * Permet de savoir si le composant est selectionne
	 */
	protected boolean estSelectionne;
	
	/**
	 * Permet de savoir si le composant est en train d'etre deplace
	 */
	protected boolean estTransfere;
	
	/**
	 * Permet de savoir si l'ombrage du composant est actif
	 */
	protected boolean ombreComposant;
	
	/**
	 * Les 4 extremites du composants, represente la selection du composant et permet d'agir sur les dimensions du composants
	 */
	protected PointExtremite pext_hd, pext_hg, pext_bd, pext_bg;
	
	/**
	 * Nom de l'extremite selectionner
	 */
	protected String extremiteSelectionnee;
	
	/**
	 * Permet de garder le centrage de la figure lors du deplacement
	 */
	private Dimension xyespace;
	
	/**
	 * Couleur de fond du composant
	 */
	protected Color couleurFond;
	
	/**
	 * Couleur de la bordure du composant
	 */
	protected Color couleurBordure;
	
	/**
	 * Couleur du texte du composant
	 */
	protected Color couleurTexte;
	
	
	/**
	 * Constructeur prenant en parametre la position du composant
	 * @param p la position du composant (coin haut gauche)
	 */
	public RepresentationComposant(Point p)
	{
		this.p=p;
		this.estSelectionne=false;
		this.estTransfere=false;
		this.ombreComposant=false;
		this.extremiteSelectionnee="";
		xyespace = new Dimension(0,0);
		
		//Couleur de bases
		couleurFond=new Color(238, 238, 238);
		couleurBordure=Color.black;
		couleurTexte=Color.black;
		
		//On calcule les points des extremites
		pext_hg=new PointExtremite(p.x,p.y);
		pext_hd=new PointExtremite(p.x+largeur,p.y);
		pext_bg=new PointExtremite(p.x,p.y+hauteur);
		pext_bd=new PointExtremite(p.x+largeur,p.y+hauteur);
		
		//On definit les dimensions du composants
		cadre=new Rectangle(p.x,p.y,largeur,hauteur);
	}
	
	/**
	 * Calcul des dimensions du composant et du positionnement des extremites
	 */
	protected void CalculGraphique()
	{
		Point pPos;
		//On calcule les points des extremites
		pPos=new Point(p.x,p.y);
		pext_hg.setPosition(pPos);
		pPos=new Point(p.x+largeur,p.y);
		pext_hd.setPosition(pPos);
		pPos=new Point(p.x,p.y+hauteur);
		pext_bg.setPosition(pPos);
		pPos=new Point(p.x+largeur,p.y+hauteur);
		pext_bd.setPosition(pPos);
		
		cadre.setBounds(p.x,p.y,largeur,hauteur);		
	}
	/**
	 * Methode abstraite a implementer
	 * Affichage graphique du composant (chaque composant possede son propre affichage)
	 */
	public abstract void dessiner(Graphics2D g2d);

	/**
	 * Permet de gerer l'effet de transparence suivant un coefficient
	 * @param alpha coefficient de tranparecne
	 * @return la composite a appliquer pour donner a un effet de transparence
	 */
	protected AlphaComposite makeComposite(float alpha)
	{
		int type = AlphaComposite.SRC_OVER;
		return(AlphaComposite.getInstance(type, alpha));
	}
	
	public void setCouleurFond(Color couleur){this.couleurFond=couleur;}
	public Color getCouleurFond(){return this.couleurFond;}
	public void setCouleurBordure(Color couleur){this.couleurBordure=couleur;}
	public Color getCouleurBordure(){return this.couleurBordure;}
	public void setCouleurTexte(Color couleur){this.couleurTexte=couleur;}
	public Color getCouleurTexte(){return this.couleurTexte;}
	
	public void setEstTransfere(boolean transferer){estTransfere=transferer;}
	public boolean getTransfere(){return estTransfere;}
	
	public void setExtremiteSelectionnee(String nom_extremite){extremiteSelectionnee=nom_extremite;}
	public String getExtremiteSelectionnee(){return extremiteSelectionnee;}
	
	public boolean getOmbreComposant(){return this.ombreComposant;}
	public void setOmbreComposant(boolean ombreComposant){this.ombreComposant=ombreComposant;}
	
	public void setPosition(Point p)
	{
		if(p.x>=0)
			this.p.x=p.x;
		else
			this.p.x=0;
		
		if(p.y>=0)
			this.p.y=p.y;
		else
			this.p.y=0;
		
		CalculGraphique();
	}
	
	public Point getPosition()
	{
		return this.p;
	}
	
	public Point getPositionCentre()
	{
		int x,y;
		
		x=p.x+(largeur/2);
		y=p.y+(hauteur/2);
		
		return new Point(x,y);
	}
	
	public void setEstSelectionner(boolean select){this.estSelectionne=select;}
	public boolean getEstSelectionner(){return this.estSelectionne;}


	
	public void setXYEspace(Dimension xyespace)
	{
		this.xyespace.width=xyespace.width;
		this.xyespace.height=xyespace.height;
	}
	
	public Dimension getXYEspace()
	{
		return this.xyespace;
	}
	
	public void setOmbre()
	{
		if(this.ombreComposant)
			this.ombreComposant=false;
		else
			this.ombreComposant=true;
	}
	
	public Dimension getDimension()
	{
		return new Dimension(cadre.width,cadre.height);
	}
	
	/**
	 * Permet de connaitre la surface du composant
	 * @return un rectangle correspondant a la surface du composant 
	 */
	public Rectangle getRectangle()
	{
		Rectangle rect_select = new Rectangle(cadre);
		rect_select.x-=3;
		rect_select.y-=3;
		rect_select.width+=6;
		rect_select.height+=6;
		return rect_select;
	}
	
	/**
	 * Deselection des 4 extremites 
	 */
	public void relacherExtremites()
	{
		pext_hg.setSelection(false);
		pext_hd.setSelection(false);
		pext_bg.setSelection(false);
		pext_bd.setSelection(false);
	}
	
	
	/**
	 * Verifie si un point est contenu dans une des extremites
	 * @param Point correspondant a un clique
	 * @return boolean si le point est contenu dans une des extremites
	 */
	public boolean intersectionExtremite(Point p)
	{
		
		if(pext_hg.Clique(p))
		{
			extremiteSelectionnee="haut_gauche";
			pext_hg.setSelection(true);
		}
		else if(pext_hd.Clique(p))
		{
			extremiteSelectionnee="haut_droite";
			pext_hd.setSelection(true);
		}
		else if(pext_bg.Clique(p))
		{
			extremiteSelectionnee="bas_gauche";
			pext_bg.setSelection(true);
		}
		else if(pext_bd.Clique(p))
		{
			extremiteSelectionnee="bas_droite";
			pext_bd.setSelection(true);
		}
		return pext_hg.getSelection()||pext_hd.getSelection()||pext_bg.getSelection()||pext_bd.getSelection();
	}
	
	/**
	 * Deplace l'extremite selectionne au prealable par intersectionExtremite()
	 * Permet de modifier les dimensions d'un composant suivant le deplacement d'une extremite
	 * @param Point contenant les coordonnees de destination
	 */
	public void deplacerExtremite(Point pnouveau)
	{
		if(extremiteSelectionnee=="haut_gauche")
		{
			if(largeur-(pnouveau.x-this.p.x)>=minLargeur)
			{
				largeur-=(pnouveau.x-this.p.x);
				this.p.x+=(pnouveau.x-this.p.x);
			}
			if(hauteur-(pnouveau.y-this.p.y)>=minHauteur)
			{
				hauteur-=(pnouveau.y-this.p.y);
				this.p.y+=(pnouveau.y-this.p.y);
			}
			
		}
		else if(extremiteSelectionnee=="haut_droite")
		{
			if(largeur+(pnouveau.x-this.p.x)-largeur>=minLargeur)
			{
				largeur+=(pnouveau.x-this.p.x)-largeur;
				this.p.x+=(pnouveau.x-this.p.x-largeur);				
			}
			
			if(hauteur-(pnouveau.y-this.p.y)>=minHauteur)
			{
				hauteur-=(pnouveau.y-this.p.y);
				this.p.y+=(pnouveau.y-this.p.y);
			}

		}
		else if(extremiteSelectionnee=="bas_gauche")
		{
			if(largeur-(pnouveau.x-this.p.x)>=minLargeur)
			{
				largeur-=(pnouveau.x-this.p.x);
				this.p.x+=(pnouveau.x-this.p.x);
			}
			
			if(hauteur+(pnouveau.y-this.p.y)-hauteur>=minHauteur)
			{
				hauteur+=(pnouveau.y-this.p.y)-hauteur;
				this.p.y+=(pnouveau.y-this.p.y)-hauteur;
			}

		}
		else if(extremiteSelectionnee=="bas_droite")
		{
			if(largeur+(pnouveau.x-this.p.x)-largeur>=minLargeur)
			{
				largeur+=(pnouveau.x-this.p.x)-largeur;
				this.p.x+=(pnouveau.x-this.p.x-largeur);
			}
			
			if(hauteur+(pnouveau.y-this.p.y)-hauteur>=minHauteur)
			{
				hauteur+=(pnouveau.y-this.p.y)-hauteur;
				this.p.y+=(pnouveau.y-this.p.y-hauteur);
			}

		}
		CalculGraphique();
	}
	
	/**
	 * Verifie si un Point est contenu dans l'objet
	 * @param Point correspondant a un clique
	 */
	public boolean intersection(Point p)
	{
		Rectangle rect_select = new Rectangle(cadre);
		rect_select.x-=3;
		rect_select.y-=3;
		rect_select.width+=6;
		rect_select.height+=6;
		if(rect_select.contains(p))
			return true;
		else
			return false;
	}
	
	/**
	 * Verifie si un rectangle entrecoupe le composant
	 * @param Rectangle correspondant a un clique
	 */
	public boolean intersection(Rectangle r)
	{
		Rectangle rect_select = new Rectangle(cadre);
		rect_select.x-=3;
		rect_select.y-=3;
		rect_select.width+=6;
		rect_select.height+=6;
		if(rect_select.intersects(r))
			return true;
		else
			return false;
	}

	public boolean dependanceHeritage(IDessinableManipulable figure)
	{
		return false;
	}
	
	public boolean dependanceAgregation(IDessinableManipulable figure)
	{
		return false;
	}

}
